/* Copyright 2008 Robert C. Brinson <rbrinson@gmail.com>
 * 
 * This file is part of PictureTagger.
 *
 * PictureTagger is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * PictureTagger is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with PictureTagger.  If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using System.IO;
using System.Collections.Generic;
using PictureTagger.ExifToolWrapper;
using PictureTagger.PictureTaggerUtility;

namespace PictureTagger.PictureCollection
{
	public class PictureRepository
	{
		private IExifToolWrapper _exifToolWrapper;
		private IDictionary<string, Picture> _pictureCollection;
		
		public PictureRepository(string pathToExifTool, string photoPath) : this(new ExifToolWrapper.ExifToolWrapper(new FileInfo(pathToExifTool)), photoPath)
		{}
		
		public PictureRepository(IExifToolWrapper wrapper, string photoPath)
		{
			_exifToolWrapper = wrapper;
			_exifToolWrapper.ReadWriteValuesAsNumbers = false;
			_pictureCollection = GetPicturesFromDirectory(photoPath);
		}
		
		public SortedDictionary<string, Picture> PictureCollection
		{
			get { return (SortedDictionary<string, Picture>) _pictureCollection; }
		}
		
		private FileInfo[] GetDirectoryFiles(string path)
		{
			List<FileInfo> files = new List<FileInfo>();
			DirectoryInfo dir = null;
			
			try
			{
				dir = new DirectoryInfo(path);
				
				if (dir != null)
				{
					foreach (FileInfo file in dir.GetFiles())
					{
						if (Path.GetExtension(file.Name) == ".jpg" || Path.GetExtension(file.Name) == ".JPG" || Path.GetExtension(file.Name) == ".jpeg" || Path.GetExtension(file.Name) == ".JPEG")
						{
							files.Add(file);
						}
					}
				}
			}
			catch (Exception)
			{
				throw;
			}
			
			return files.ToArray();
		}
		
		private IDictionary<string, Picture> GetPicturesFromDirectory(string path)
		{
			SortedDictionary<string, Picture> collection = new SortedDictionary<string, Picture>();
			Dictionary<string, IDictionary<string, string>> fileTags = null;
			Dictionary<FileInfo, byte[]> picThumbnails = null;
			List<string> tags = null;
			Picture image;
			string fileHeadline = String.Empty;
			string fileCaption = String.Empty;
			List<string> fileKeywords = null;
			
			FileInfo[] selectedFiles = GetDirectoryFiles(path);

			if (selectedFiles.Length > 0)
			{
				fileKeywords = new List<string>();
				tags = new List<string>();
				
				tags.Add(ExifToolTags.IPTC_HEADLINE);
				tags.Add(ExifToolTags.IPTC_CAPTION);
				tags.Add(ExifToolTags.IPTC_KEYWORDS);
				
				try
				{
					fileTags = (Dictionary<string, IDictionary<string, string>>) _exifToolWrapper.GetTagsFromFiles(selectedFiles, tags);
					picThumbnails = (Dictionary<FileInfo, byte[]>) _exifToolWrapper.GetBinaryTagFromFiles(selectedFiles, ExifToolTags.THUMBNAIL);
				}
				catch (Exception)
				{
					throw;
				}
				
				foreach (FileInfo pic in picThumbnails.Keys)
				{
					foreach (string tag in fileTags[pic.FullName].Keys)
					{
						switch (tag)
						{
							case ExifToolTags.IPTC_HEADLINE:
								fileHeadline = fileTags[pic.FullName][tag];
								break;
							case ExifToolTags.IPTC_CAPTION:
								fileCaption = fileTags[pic.FullName][tag];
								break;
							case ExifToolTags.IPTC_KEYWORDS:
								string keywords = fileTags[pic.FullName][tag];
								string[] keys = keywords.Split(',');
								foreach (string key in keys)
								{
									fileKeywords.Add(key.Trim());
								}
								break;
						}
					}
					
					image = new Picture(pic.FullName, fileHeadline, fileCaption, fileKeywords, (picThumbnails[pic].Length == 0) ? ImageUtility.GenerateImageThumbnail(pic.FullName) : picThumbnails[pic]);
					collection.Add(pic.Name, image);
					
					fileHeadline = String.Empty;
					fileCaption = String.Empty;
					fileKeywords = new List<string>();
				}
			}
			
			return collection;
		}
		
		public bool PictureCollectionIsDirty()
		{
			bool dirty = false;
			
			if (_pictureCollection != null)
			{
				foreach (string photo in _pictureCollection.Keys)
				{
					if (_pictureCollection[photo].IsDirty)
					{
						dirty = true;
						break;
					}
				}
			}
			
			return dirty;
		}
		
		public void ResetPictureCollection()
		{
			if (_pictureCollection != null && _pictureCollection.Count > 0)
			{
				foreach (string picture in _pictureCollection.Keys)
				{
					if (_pictureCollection[picture].IsDirty)
					{
						_pictureCollection[picture].Reset();
					}
				}
			}
		}
		
		public bool SavePictureCollection()
		{
			Dictionary<string, string> tags;
			bool success = true;
			string exifToolReturn;
			
			if (_pictureCollection != null)
			{
				foreach (string file in _pictureCollection.Keys)
				{
					if (_pictureCollection[file].IsDirty)
					{
						exifToolReturn = String.Empty;
						tags = new Dictionary<string, string>();
						
						if (_pictureCollection[file].IsHeadlineDirty)
						{
							tags.Add(ExifToolTags.IPTC_HEADLINE, _pictureCollection[file].Headline);
							tags.Add(ExifToolTags.XMP_HEADLINE, _pictureCollection[file].Headline);
						}
						if (_pictureCollection[file].IsCaptionDirty)
						{
							tags.Add(ExifToolTags.IPTC_CAPTION, _pictureCollection[file].Caption);
							tags.Add(ExifToolTags.XMP_DESCRIPTION, _pictureCollection[file].Caption);
						}
						if (_pictureCollection[file].IsKeywordsDirty)
						{
							System.Text.StringBuilder keyString = new System.Text.StringBuilder();
							foreach (string keyword in _pictureCollection[file].Keywords)
							{
								keyString.Append(keyword).Append(",");
							}
							keyString = keyString.Remove(keyString.Length - 1, 1);
							tags.Add(ExifToolTags.IPTC_KEYWORDS, keyString.ToString());
							tags.Add(ExifToolTags.XMP_SUBJECT, keyString.ToString());
						}
						
						try
						{
							exifToolReturn = _exifToolWrapper.SetTagsToFile(new FileInfo(_pictureCollection[file].FullName), tags);
							success = success && exifToolReturn.Contains("image files updated");
						}
						catch (Exception)
						{
							throw;
						}
						_pictureCollection[file].CleanDirtyFlags();
					}
				}
			}
			return success;
		}
		
		private IMetaDataSpecification GetRelevantMetaDataSpecification(string metaDataName)
		{
			IMetaDataSpecification spec = null;
			
			foreach (IMetaDataSpecification metaDataSpec in MetaDataSpecificationFactory.MetaDataSpecs)
			{
				if (metaDataSpec.Check(metaDataName))
				{
					spec = metaDataSpec;
				}
			}
			
			return spec;
		}
		
		public void SetMetaDataTag(string file, string metaDataName, string metaDataValue)
		{
			Picture pic = _pictureCollection[file];
			IMetaDataSpecification metaDataSpec = GetRelevantMetaDataSpecification(metaDataName);
			metaDataSpec.UpdateMetaData(ref pic, metaDataValue);
			_pictureCollection[file] = pic;
		}
		
		public void ResetMetaDataTag(string file, string metaDataName)
		{
			Picture pic = _pictureCollection[file];
			IMetaDataSpecification metaDataSpec = GetRelevantMetaDataSpecification(metaDataName);
			metaDataSpec.ResetMetaData(ref pic);
			_pictureCollection[file] = pic;
		}	
	}
}